//
// Nibbler.cpp for Nibbler in /home/titouan/Dropbox/Code/nibbler-epitech-2017/src
//
// Made by Titouan Creach
// Login   <titouan@epitech.net>
//
// Started on  Sat Mar 22 18:03:07 2014 Titouan Creach
// Last update Mon Mar 24 14:16:09 2014 Titouan Creach
//

#include "Point.hpp"
#include "Nibbler.hpp"
#include "Pomme.hpp"
#include <ctime>
#include <sstream>
#include <cstdlib>
#include <deque>

Nibbler::Nibbler(IGraph *g, int w, int h)
  : _g(g)
  , _snake(w, h)
  , _pomme(w, h)
  , _w(w)
  , _h(h)
  , _time(150)
{
  srand(time(NULL));
  _loadMap[IGraph::BODY] = "./res/snake.gif";
  _loadMap[IGraph::POMME] = "./res/pomme.png";
  _loadMap[IGraph::BORDURE] = "./res/block.png";
  _loadMap[IGraph::HEAD] = "./res/snake_head.gif";
  g->loadImages(_loadMap);
  g->loadFont("./res/DS-DIGI.TTF");
}

void Nibbler::displayBordure()
{
  for (int i = 0 ; i < _w / 16 ; ++i)
    {
      for (int j = 0; j < _h / 16 ; ++j)
	{
	  if (i == 0 || j == 0 || j == (_h / 16) - 1 || i == (_w / 16) -1)
	    _g->drawBlock(IGraph::BORDURE, i * 16, j * 16);
	}
    }
}

bool Nibbler::collisionSnakeBordure()
{
  Point p;
  std::deque<Point> snakeBody;

  snakeBody = _snake.getPointList();
  p = snakeBody[0];

  for (int i = 0 ; i < _w / 16 ; ++i)
    {
      for (int j = 0; j < _h / 16 ; ++j)
	{
	  if (i == 0 || j == 0 || j == (_h / 16) - 1 || i == (_w / 16) -1)
	    {
	      if (i == p.x && j == p.y)
		return (true);
	    }
	}
    }
  return (false);
}

bool Nibbler::collisionSnakeSnake()
{
  std::deque<Point> snakeBody;
  std::deque<Point>::iterator it;
  Point p;

  snakeBody = _snake.getPointList();
  p = snakeBody[0];
  it = snakeBody.begin();
  ++it;

  for ( ; it != snakeBody.end() ; ++it)
    {
      if (it->x == p.x && it->y == p.y)
	return (true);
    }
  return (false);
}

void  Nibbler::displaySnake()
{
  std::deque<Point> snakeBody;

  snakeBody = _snake.getPointList();
  std::deque<Point>::iterator it;

  for (it = snakeBody.begin() ; it != snakeBody.end() ; ++it)
    {
      if (it == snakeBody.begin())
        _g->drawBlock(IGraph::HEAD, it->x * 16, it->y * 16);
      else
        _g->drawBlock(IGraph::BODY, it->x * 16, it->y * 16);
    }
}

void Nibbler::collisionSnakePomme()
{
  Point pommePos;
  std::deque<Point> snakeBody;
  std::deque<Point>::iterator it;

  pommePos = _pomme.getPosition();
  snakeBody = _snake.getPointList();

  for (it = snakeBody.begin() ; it != snakeBody.end() ; ++it)
    {
      if (it->x == pommePos.x && it->y == pommePos.y)
	{
	  _snake.addNode();
	  _pomme.newPomme(snakeBody);
	  return;
	}
    }
}

const std::string Nibbler::getScoreAsString() const
{
  std::size_t score;
  std::stringstream ss;

  score = _snake.getScore();
  ss << "Score : " << score;
  return ss.str();
}

void Nibbler::displayPomme()
{
  Point pommePoint;

  pommePoint = _pomme.getPosition();
  _g->drawBlock(IGraph::POMME, pommePoint.x * 16, pommePoint.y * 16);
}

void Nibbler::screenScore() const
{
   Point p1, p2, p3;
   int x1, x2, x3, y1, y2, y3;
   const std::string s1(getScoreAsString());
   const std::string s2("Too bad");
   const std::string s3("Appuyez sur une touche pour quitter");

   p1 = _g->getTextSize(s1);
   p2 = _g->getTextSize(s2);
   p3 = _g->getTextSize(s3);

   x1 = (_w - p1.x) / 2;
   y1 = (_h - p1.y) / 2;

   x2 = (_w - p2.x) / 2;
   y2 = (y1 - p2.y - 16);

   x3 = (_w - p3.x) / 2;
   y3 = (y1 + p1.y + 16);

   _g->writeText(0xff, 0xff, 0xff, s2, x2, y2);
   _g->writeText(0xff, 0xff, 0xff, s1, x1, y1);
   _g->writeText(0xff, 0xff, 0xff, s3, x3, y3);

   _g->display();
   _g->pause();
}

void Nibbler::run()
{
  int	finish = 0;
  unsigned int after, before;

  _g->openWindow();

  _pomme.newPomme(_snake.getPointList());
  _g->display();
  while (!finish)
    {
      before = _g->getCurrentTime();

      /* Events */
      _e = _g->getNextEvent();
      if (_e == IGraph::QUIT)
	finish = 1;
      if (_e == IGraph::UP)
	_snake.move(Snake::UP);
      if (_e == IGraph::DOWN)
	_snake.move(Snake::DOWN);
      if (_e == IGraph::RIGHT)
	_snake.move(Snake::RIGHT);
      if (_e == IGraph::LEFT)
	_snake.move(Snake::LEFT);

      /* Display */
      _g->clearScreen(0, 0, 0);
      collisionSnakePomme();
      displaySnake();
      displayPomme();
      displayBordure();
      _snake.update();
      _g->writeText(255, 255, 255, getScoreAsString(), 30, 30);
      _g->display();

      if (collisionSnakeSnake() || collisionSnakeBordure())
        {
          screenScore();
          finish = 1;
        }

      after = _g->getCurrentTime();

      /* Wait */
      if ((after - before) < _time)
	{
	  _g->wait(_time - (after - before));
    if (_time > 50)
      _time -= 1;
	}
    }
}
